package com.mytijian.runtime;

import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.mytijian.WebExceptionEnum;
import com.mytijian.exception.BizException;
import com.mytijian.openapi.adapter.alihalt.exception.AlihaltException;
import com.mytijian.openapi.adapter.dingding.exception.DingDingException;
import com.mytijian.runtime.DataSignUtil.DataCheckResult;
import com.mytijian.runtime.executor.ServiceExecutor;
import com.mytijian.runtime.model.param.AliCommonParam;
import com.mytijian.runtime.resolver.AliCodeMerchantRequestParamResolver;
import com.mytijian.runtime.resolver.AliHealthRequestParamResolver;
import com.mytijian.runtime.resolver.AliRequestParamResolver;

@Component
public class ServiceExecutorFacade {

	private Logger log = LoggerFactory.getLogger(ServiceExecutorFacade.class);

	@Autowired
	private ServiceExecutor serviceExecutor;
	@Autowired
	private RequestIdCheckHelper requestIdCheckHelper;

	@Value("${aliApp.health.appSecret}")
	public String healthAppSecret;

	@Value("${aliApp.codeMerchant.notifySecret}")
	public String codeMchNotifySecret;

	public void executeAliCodeMchService(HttpServletRequest request, HttpServletResponse response) throws Exception {
		// 防重校验
		requestIdCheckHelper.checkRequestId(request.getParameter("requestId"));
		// 请求参数验签；
		DataCheckResult checkResult = DataSignUtil.checkCodeMerchantSign(request, codeMchNotifySecret);
		// 获取请求参数
		Map<String, Object> params = getRequestParams(request);
		log.info("调用码商服务service=[{}], params={}, body= {}", params.get("method"), JSON.toJSONString(params),
				checkResult.getRequestBody());
		if (checkResult.isSuccess()) {
			executeAliCodeMchServiceWithException(response, params);
		}
		// 参数签名错误
		throw new BizException(WebExceptionEnum.DATA_SIGN_INVALID);
	}

	private void executeAliCodeMchServiceWithException(HttpServletResponse response, Map<String, Object> params)
			throws Exception {
		try {
			executeService(params, null, response, new AliCodeMerchantRequestParamResolver());
			log.info("调用码商服务service=[{}]成功", params.get("method"));
			return;
		} catch (BizException e) {
			log.warn("调用码商服务service=[{}]失败:", params.get("method"), e);
			throw e;
		} catch (Exception e) {
			log.error("调用码商服务service=[{}]失败", params.get("method"), e);
			throw e;
		}

	}

	public void executeAliHealthService(HttpServletRequest request, HttpServletResponse response) {
		DataCheckResult checkResult = null;
		// 请求参数验签
		
		// FIXME 上线之前删除这段判断逻辑，暂时为方便阿里健康前端调试
//		if (request.getParameter("app_key").startsWith("10")) {
//			log.info("测试key, 不校验---------------------------");
//			checkResult = new DataCheckResult();
//			checkResult.setSuccess(true);
//			try {
//				BufferedReader reader = request.getReader();
//				StringBuilder sb = new StringBuilder();
//				String t = null;
//				while((t=reader.readLine())!=null) {
//					sb.append(t);
//				}
//				checkResult.setRequestBody(sb.toString());
//			} catch (IOException e) {
//				e.printStackTrace();
//				log.error("执行错误{}",e);
//			}
//			
//		} else {
			checkResult = DataSignUtil.checkSign(request, healthAppSecret);
//		}
		// 获取请求参数
		Map<String, Object> params = getRequestParams(request);
		log.info("[阿里健康] 调用阿里健康服务service=[{}], params={}, body= {}", params.get("method"), JSON.toJSONString(params),
				checkResult.getRequestBody());
		if (checkResult.isSuccess()) {
			executeAliHealthServiceWithException(response, checkResult, params);
			return;
		}
		// 参数签名错误
		throw new AlihaltException("400", "data sign failed.");
	}
	
	public void executeDingDingService(HttpServletRequest request, HttpServletResponse response)
			throws IOException {
		// 请求参数验签
		 DataCheckResult checkResult = DataSignUtil.checkSign(request, healthAppSecret);
		// 获取请求参数
		Map<String, Object> params = getRequestParams(request);
		JSONObject json = JSONObject.parseObject(checkResult.getRequestBody());
		if(json != null){
			params.forEach((key, val) -> {
				json.put(key, val);
			});
		}
		log.info("[钉钉] 调用钉钉服务service=[{}], params={}, body= {}", params.get("method"), JSON.toJSONString(params),
				checkResult.getRequestBody());
		if (checkResult.isSuccess()) {
			executeDingDingWithException(response, json != null ?json.toJSONString():JSONObject.toJSONString(params), params);
			return;
		}
		// 参数签名错误
		throw new DingDingException("400", "data sign failed.");
	}

	private void executeDingDingWithException(HttpServletResponse response, String body,
			Map<String, Object> params) {
		try {
			executeService(params, body, response, new AliHealthRequestParamResolver());
			log.info("[钉钉] 调用钉钉服务service=[{}]成功", params.get("method"));
			return;
		} catch (DingDingException e) {
			log.warn("[钉钉] 调用钉钉服务service=[{}]失败", params.get("method"));
			throw e;
		} catch (RuntimeException e) {
			log.warn("[钉钉] 调用钉钉服务service=[{}]失败", params.get("method"));

			if (e.getCause() instanceof DingDingException) {
				throw (DingDingException) e.getCause();
			}
			throw new DingDingException("500", "unknow exception");
		}
	}
	
	private void executeAliHealthServiceWithException(HttpServletResponse response, DataCheckResult checkResult,
			Map<String, Object> params) {
		try {
			executeService(params, checkResult.getRequestBody(), response, new AliHealthRequestParamResolver());
			log.info("[阿里健康] 调用阿里健康服务service=[{}]成功", params.get("method"));
			return;
		} catch (AlihaltException e) {
			log.warn("[阿里健康] 调用阿里健康服务service=[{}]失败", params.get("method"));
			throw e;
		} catch (RuntimeException e) {
			log.warn("[阿里健康] 调用阿里健康服务service=[{}]失败", params.get("method"));

			if (e.getCause() instanceof AlihaltException) {
				throw (AlihaltException) e.getCause();
			}
			throw new AlihaltException("500", "unknow exception");
		}
	}

	private void executeService(Map<String, Object> reqParams, String msgBody, HttpServletResponse response,
			AliRequestParamResolver<?> resolver) {
		//压测数据直接返回
		String isPerfReq = reqParams.get("isPerfReq") == null ? "" : String.valueOf(reqParams.get("isPerfReq"));
		if("true".equalsIgnoreCase(isPerfReq)){
			Map<String, String> result = new HashMap<String, String>();
			result.put("code", "isv.success-all");
			result.put("msg", "成功");
			packageAndoutputResult(response, result);
			return;
		}
		// 解析请求参数
		AliCommonParam reqParam = resolver.resolver(reqParams);
		// 服务执行
		Object result = serviceExecutor.execute(reqParam, msgBody);
		// 服务返回数据打包
		packageAndoutputResult(response, result);

	}

	private void packageAndoutputResult(HttpServletResponse response, Object result) {
		try {
			String resultJSON = JSON.toJSONString(result);
			response.getWriter().print(resultJSON);
		} catch (IOException | JSONException ex) {
			log.error("数据输出异常", ex);
			throw new BizException(WebExceptionEnum.DATA_OUT_PUT_ERROR);
		}
	}

	private Map<String, Object> getRequestParams(HttpServletRequest request) {
		// 获取请求所有参数
		Enumeration<String> paramNames = request.getParameterNames();
		Map<String, Object> params = new HashMap<String, Object>();
		while (paramNames.hasMoreElements()) {
			String paramName = paramNames.nextElement();
			params.put(paramName, request.getParameter(paramName));
		}
		return params;
	}
}
